package com.nut.lmsc.service.impl;

import cn.hutool.http.HttpUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.nut.lmsc.api.req.PrepayReq;
import com.nut.lmsc.api.req.RefundReq;
import com.nut.lmsc.api.resp.PrepayResp;
import com.nut.lmsc.api.resp.WeChatAuthResponse;
import com.nut.lmsc.common.Constants;
import com.nut.lmsc.common.PayInfo;
import com.nut.lmsc.common.RefundInfo;
import com.nut.lmsc.common.Result;
import com.nut.lmsc.jbb.JbbService;
import com.nut.lmsc.redis.RedisKeys;
import com.nut.lmsc.entity.*;
import com.nut.lmsc.enums.OrderStatusEnum;
import com.nut.lmsc.interceptor.AdminJwt;
import com.nut.lmsc.mapper.*;
import com.nut.lmsc.redis.RedisLock;
import com.nut.lmsc.service.PayService;
import com.nut.lmsc.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class PayServiceImpl implements PayService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderActionLogMapper orderActionLogMapper;

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private AdapayPayRecordMapper adapayPayRecordMapper;

    @Autowired
    private AdapayRefundRecordMapper adapayRefundRecordMapper;

    @Autowired
    private JbbService jbbService;

    @Autowired
    private OrderSsnMapper orderSsnMapper;

    @Override
    public Result<String> prepay(String orderId, HttpServletResponse response) {

        Order order = orderMapper.selectByOrderId(orderId);
        if (order == null) {
            return Result.fail("找不到订单");
        }

        //检查订单状态
        if (order.getStatus() != OrderStatusEnum.INIT.getValue()) {
            //订单不能支付
            return Result.fail("订单不能支付");
        }

        PrepayReq req = new PrepayReq();
        req.setOrderNo(orderId.toString());
        req.setPayWay(1);

        if (SpringUtil.isProd()) {
            req.setPayMoney(order.getRealMoney());
        } else {
            req.setPayMoney(1);
        }

//        req.setPayMoney(order.getRealMoney());
        req.setBizNo(order.getMemberId().toString());
        req.setBody("test");

        PrepayResp resp = jbbService.payPrepay(req);

        //记录ssn与orderId对应关系
        OrderSsn orderSsn = new OrderSsn();
        orderSsn.setOrderId(req.getOrderNo());
        orderSsn.setSsn(resp.getPayNo());
        orderSsn.setQueryUrl(resp.getQueryUrl());
        orderSsnMapper.insert(orderSsn);

        if (response != null) {
            try {
                BitMatrix bm = new MultiFormatWriter().encode(resp.getQrcodeUrl(), BarcodeFormat.QR_CODE, 200, 200);
                response.setHeader("Content-Type", "image/png");
                MatrixToImageWriter.writeToStream(bm, "png", response.getOutputStream());
            } catch (Exception ex) {
                log.info("error", ex);
            }
        }

        return Result.ok(resp.getQrcodeUrl());
    }

    @Override
    public void callback(JsonNode jsonNode, String json) {

        try {

            String orderId = jsonNode.get("orderNo").asText();
            String payNo = jsonNode.get("payNo").asText();

            String payStatus = jsonNode.get("payStatus").asText();
            String payChannel = jsonNode.get("payChannel").asText();
            String payAmt = jsonNode.get("payAmt").asText();


            //验签成功逻辑

            String redisKey = RedisKeys.getOrderKey(payNo);
            Boolean isLock = redisLock.tryLock(redisKey, Constants.REQUEST_ID, 5, TimeUnit.SECONDS);
            if (!isLock) {
                log.info("get_redis_key_fail=," + redisKey);
                return;
            }

            Order order = orderMapper.selectByOrderId(orderId);
            if (order == null) {
                return;
            }
            //检查订单状态
            if (order.getStatus() >= OrderStatusEnum.HAS_PAID.getValue()) {
                log.info("order_has_paid,orderId=" + orderId);
                return;
            }

            if (SUCCESS.equalsIgnoreCase(payStatus)) {

                AdapayPayRecord record = new AdapayPayRecord();
                record.setPayNo(payNo);
                record.setOrderId(orderId);
                record.setMoney(payAmt);
                record.setChannel(payChannel);
                record.setStatus(payStatus);
                record.setJson(json);
                adapayPayRecordMapper.insert(record);

                doPaySuccess(order.getId(), orderId, payChannel);
            }

        } catch (Exception e) {
            //{"app_id":"app_4a6f810d-482b-498b-be39-27a0b4cda0a5","created_time":"20230717201119","description":"","end_time":"20230717201134","expend":{"buyer_logon_id":"159****5243","cashPayAmt":"12.00","sub_open_id":"2088612753476485"},"fee_amt":"0.07","id":"002212023071720111810526987466469789696","order_no":"1689595878567446","out_trans_id":"2023071722001476481455940573","party_order_id":"02212307177267911009619","pay_amt":"12.00","pay_channel":"alipay_qr","real_amt":"12.00","share_eq":"Y","status":"succeeded","trans_response_add_info":"{\"fund_bill_list\":[{\"amount\":\"12.00\",\"fund_channel\":\"ALIPAYACCOUNT\"}]}"},
            log.error("callback_error", e);
        }
    }

    @Override
    public void doPaySuccess(String orderId, String payChannel) {
        Order order = orderMapper.selectByOrderId(orderId);
        if (order == null) {
            return;
        }

        doPaySuccess(order.getId(), orderId, payChannel);
    }

    @Override
    public Result queryIsPaid(String orderId) {

        List<OrderSsn> list = orderSsnMapper.selectByOrderId(orderId);

        for (OrderSsn orderSsn : list) {

            PayInfo payInfo = jbbService.queryPayResult(orderSsn.getSsn());
            if (payInfo != null && SUCCESS.equalsIgnoreCase(payInfo.getPayStatus())) {

                AdapayPayRecord payRecord = adapayPayRecordMapper.selectByOrderId(orderId);

                if (payRecord == null) {
                    AdapayPayRecord record = new AdapayPayRecord();
                    record.setPayNo(payInfo.getPayNo());
                    record.setOrderId(orderId);
                    record.setMoney(payInfo.getPayAmt());
                    record.setChannel(payInfo.getPayChannel());
                    record.setStatus(payInfo.getPayStatus());
                    adapayPayRecordMapper.insert(record);
                }

                doPaySuccess(orderId, payInfo.getPayChannel());

                break;
            }
        }


        return Result.ok();
    }

    @Transactional(rollbackFor = Exception.class)
    public void doPaySuccess(Integer id, String orderId, String payChannel) {

//        String code = generateCode();

        //更新订单支付成功
        Order update = new Order();
        update.setId(id);
        update.setPayChannel(payChannel);
        update.setPayTime(DateUtil.getNowDateTime());
        update.setStatus(OrderStatusEnum.HAS_PAID.getValue());
        orderMapper.updateById(update);

        OrderActionLog actionLog = new OrderActionLog();
        actionLog.setOrderId(orderId);
        actionLog.setFroms("系统");
        actionLog.setAction("已支付");
        orderActionLogMapper.insert(actionLog);

        //TODO 生成兑换码

    }

    @Override
    public Result refund(RefundReq req, AdminJwt adminJwt) {

        String redisKey = RedisKeys.getOrderKey(req.getOrderId());
        Boolean isLock = redisLock.tryLock(redisKey, Constants.REQUEST_ID, 5, TimeUnit.SECONDS);
        if (!isLock) {
            log.info("get_redis_key_fail=," + redisKey);
            return Result.fail("稍后再试");
        }

        String orderId = req.getOrderId();
        Integer money = req.getMoney();

        Order order = orderMapper.selectByOrderId(orderId);
        if (order == null) {
            return Result.fail("找不到订单");
        }
        //检查订单状态
        if (order.getStatus() != OrderStatusEnum.HAS_PAID.getValue() &&
                order.getStatus() != OrderStatusEnum.CANCEL.getValue()) {
            log.info("order_not_refund,orderId=" + orderId);
            return Result.fail("订单状态不对");
        }

        AdapayPayRecord payRecord = adapayPayRecordMapper.selectByOrderId(orderId);

        if (payRecord == null) {
            log.info("no_pay_records,orderId=" + orderId);
            return Result.fail("没有支付记录");
        }

        int payMoney = MathUtil.toFen(payRecord.getMoney());
        if (payMoney < money) {
            log.info("refund_money_is_larger,orderId={},payMoney={},refundMoney={}", orderId, payMoney, money);
            return Result.fail("退款金额不能超过支付金额");
        }

        String payNo = payRecord.getPayNo();

        RefundInfo refund = jbbService.refund(payNo, money);
        if (refund == null) {
            return Result.fail("退款报错");
        }

        //退款成功
        if (PENDING.equalsIgnoreCase(refund.getStatus())) {

            AdapayRefundRecord record = new AdapayRefundRecord();
            record.setPayNo(payNo);
            record.setOrderId(orderId);
            record.setPayNo(payNo);
            record.setRefundId(refund.getRefundId());
            record.setRefundAmt(refund.getRefundAmt());
            record.setPayStatus(refund.getStatus());
            adapayRefundRecordMapper.insert(record);

            Order update = new Order();
            update.setId(order.getId());
            update.setRefundMoney(money);
            update.setStatus(OrderStatusEnum.CLOSED.getValue());
            orderMapper.updateById(update);

            OrderActionLog actionLog = new OrderActionLog();
            actionLog.setOrderId(orderId);
            actionLog.setFroms("系统");
            actionLog.setAction("退款");
            actionLog.setUsername(adminJwt.getUsername());
            actionLog.setUserId(adminJwt.getUserId());
            orderActionLogMapper.insert(actionLog);

            return Result.ok();

        }

        return Result.fail(refund.getMsg());
    }

    public static final int TRY_COUNT = 3;

    private String generateCode() {
        int index = 0;
        while (index < TRY_COUNT) {
            String code = CharUtil.getRandomNum(6);
            Integer count = orderMapper.selectByCode(code);
            if (count == 0) {
                return code;
            }
            index++;
        }
        return Constants.DEFAULT_PWD;
    }

    public static final String appId = "wx4a66980d2937027e";
    public static final String appSecret = "c2a5dff15d97891400b782d7c71fdb25";

//    public static final String appId = "wx2514b407b4666f8d";
//    public static final String appSecret = "7a9721a5325f21f930da0e6aacdaa08b";

    private static String getOpenId(String code) {

        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
        url = String.format(url, appId, appSecret, code);

        log.info("wx_auth_url=" + url);

        String json = HttpUtil.get(url);

        //{"errcode":40163,"errmsg":"code been used, rid: 64c0b4e2-4a13c44e-6df87362"}
        //{"access_token":"70_y86oKHYt1PQOso6OhJdmau65c_TDdEUzSDqMIyyORFqqxVcJRnElJfeBvj-B1JloNehCq595BXgb8JjpubL9DO_FgO5JejseHfP6jzyJy3k","expires_in":7200,"refresh_token":"70_CEjvbLb4AG9kZVwmYyh7HdcTCEmV-GivSh1sq1RDBbRL8pd8pd2KOI3CKmYxLF9545eVTgDGkYIXF_ru4Izj6YC5d82JrzuvZYLBmoxk8XU","openid":"os2nJ6Oz6uM3lAG00ifr8Xodlg_g","scope":"snsapi_base"}
        log.info("wx_auth_resp=" + json);

        WeChatAuthResponse resp = JacksonUtils.toObj(json, WeChatAuthResponse.class);

        return resp.getOpenid();
    }

    public static void main(String[] args) {
        String code = "031YZMFa1inoHF05yLGa1LwbGH1YZMFj";
        String openId = getOpenId(code);
        System.out.println(openId);

    }
}